package org.summerframework.core.jackson;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author 石超
 * @version v1.0.0
 */
public class JsonEnumSerializer<T extends Number> extends StdSerializer<T> implements ContextualSerializer {
    private Class enumClass;
    private Method getInstance;
    private Method getValue;
    private String name;
    private String instanceMethod;
    private String describeMethod;
    private Boolean getMethod = false;

    public JsonEnumSerializer() {
        super((Class<T>) Integer.class);
    }

    public JsonEnumSerializer(Class<T> t, JsonEnum jsonEnum) {
        super(t);
        this.enumClass = jsonEnum.value();
        this.name = jsonEnum.name();
        this.instanceMethod = jsonEnum.instanceMethod();
        this.describeMethod = jsonEnum.describeMethod();

        if (enumClass != null) {
            try {
                if (getInstance == null) {
                    getInstance = enumClass.getMethod(this.instanceMethod, t);

                    getInstance.setAccessible(true);
                }
                if (getValue == null) {
                    getValue = enumClass.getMethod(this.describeMethod);
                    getInstance.setAccessible(true);
                }

                getMethod = true;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void serialize(Number value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        NumberSerializer.instance.serialize(value, gen, serializers);
        String key = gen.getOutputContext().getCurrentName();
        key = StringUtils.isNotBlank(this.name) ? this.name : key + "Name";

        gen.writeFieldName(key);

        if (value != null && getMethod) {
            try {
                Object invoke = getInstance.invoke(null, value);
                final Object invokeValue = getValue.invoke(invoke);

                if (invokeValue != null) {
                    ToStringSerializer.instance.serialize(invokeValue, gen, serializers);
                    return;
                }
            } catch (Exception ignored) {
            }
        }

        gen.writeString("");
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) { // 为空直接跳过
            JsonEnum annotation = beanProperty.getAnnotation(JsonEnum.class);
            if (annotation == null) {
                annotation = beanProperty.getContextAnnotation(JsonEnum.class);
            }
            if (annotation != null) { // 如果能得到注解，就将注解的 value 传入 ImageURLSerialize
                return new JsonEnumSerializer(beanProperty.getType().getRawClass(), annotation);
            }

            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }

        return serializerProvider.findNullValueSerializer(beanProperty);
    }

    private Method getClass(Class classs, String key) {
        StringBuffer sb = new StringBuffer();
        sb.append("get");
        sb.append(key.substring(0, 1).toUpperCase());
        sb.append(key.substring(1));

        try {
            return classs.getDeclaredMethod(sb.toString());
        } catch (NoSuchMethodException e) {
            if (classs.getSuperclass() != null) {
                return getClass(classs.getSuperclass(), key);
            }
        }

        return null;
    }

    private Field getField(Class classs, String key) {

        try {
            return classs.getDeclaredField(key);
        } catch (NoSuchFieldException e) {
            if (classs.getSuperclass() != null) {
                return getField(classs.getSuperclass(), key);
            }
        }

        return null;
    }
}
